
#ifndef  FRAME_ASIO_IMPL_H
#define  FRAME_ASIO_IMPL_H

#include <boost/asio.hpp>
#include <boost/array.hpp>


#include "Impl.h"
#include "NetFrameImplFactory.h"

namespace frame {
   class IChannel; 
}

namespace frame  {
namespace impl {
namespace asio {


class AsioChannelImpl : public ChannelImpl , public std::enable_shared_from_this<AsioChannelImpl>{
public:
    typedef std::shared_ptr<AsioChannelImpl> Ptr;

    AsioChannelImpl(ChannelHandlerImpl::Ptr handler, boost::asio::io_context & io, const std::string & ip, int remotePort);
    ~AsioChannelImpl() override;
    int open() override ;
    int close() override ;

    bool isOpen() const { return  opened; }

    int read(IReadBufferImpl::Ptr readBuffer) override;
    int write(IWriteBufferImpl::Ptr writeBuffer) override;

    int disconnect() override ;

    ChannelHandlerImpl::Ptr getHandlerImpl() const override {
        return handler;
    }

public:
    // *******************  asio special code *******************
    boost::asio::ip::tcp::socket & getSocket() {
        return socket;
    }
    boost::asio::ip::tcp::endpoint & getEndpoint(){
        return endpoint;
    }

private:
    void handleRead(const boost::system::error_code & error, size_t bytes_transferred);
    void handleWrited(const boost::system::error_code & error, size_t bytes_transferred);

private:
    bool opened;
    ChannelHandlerImpl::Ptr handler;
    std::weak_ptr<IChannel> channel;

    boost::asio::io_context & io;
    boost::asio::ip::tcp::socket socket;
    boost::asio::ip::tcp::endpoint endpoint;

    IReadBufferImpl::Ptr readBuffer;
    IWriteBufferImpl::Ptr writeBuffer;
    //std::shared_ptr<boost::asio::mutable_buffer> readBuffer;
    //std::shared_ptr<boost::asio::const_buffer> writeBuffer;
};

class AsioServiceImpl : public ServiceImpl {
public:
    typedef std::shared_ptr<AsioServiceImpl> Ptr;
    AsioServiceImpl();
    ~AsioServiceImpl() override;
    int start() override;
    int run() override;
    void stop() override;

public:
    boost::asio::io_context & getIoContext(){
        return io;
    }
private:
    boost::asio::io_context io;
};


class AsioClientImpl : public ClientImpl, public std::enable_shared_from_this<AsioClientImpl> {
public:
    typedef std::shared_ptr<AsioClientImpl> Ptr;

    AsioClientImpl(AsioServiceImpl::Ptr serviceImpl, ConnectHandlerImpl::Ptr connectHandlerImpl);
    ~AsioClientImpl() override;

    ChannelImpl::Ptr connect(const std::string & remoteIp, const int remotePort, ChannelHandlerImpl::Ptr channelHandlerImpl) override;

    int open() override ;
    int close() override ;

public:
    
private:
    void asyncConnect(std::shared_ptr<AsioChannelImpl> impl);
    void handleConnect(std::shared_ptr<AsioChannelImpl> impl, const boost::system::error_code & error);

private:
    std::weak_ptr<AsioServiceImpl> serviceImpl;
    ConnectHandlerImpl::Ptr connectHandlerImpl;
    boost::asio::io_context & io;
};




class AsioImplFactory : public ImplFactory {
public:
    ClientImpl::Ptr createClient(ServiceImpl::Ptr serviceImpl, ConnectHandlerImpl::Ptr connectHandlerImpl) override ;
    ServiceImpl::Ptr createService() override ;
};


} // end of namespace asio
} // end of namespace impl
} // end of namespace frame



#endif   /* FRAME_ASIO_IMPL_H */
